//
//  main.cpp
//  DCA
//
//  Created by James Critchley on 7/26/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#include <iostream>
#include <pthread.h>

#include "Sys3D.h"
#include "Quaternion.h"
#include "Rotation.h"

#include "DCFlowControl.h"
#include "DCAComputation.h"

#include "Timer.h"

void *ThreadFunction(void *s)
{        
    DCFlowControl *dca = (DCFlowControl*) s;
    while(1){
//             dca->kinAssembly_traversal();
//             dca->kinSolve_traversal();
//             dca->EOM_traversal();            
            dca->assembly_traversal();                
            dca->solve_traversal();
    }
    return 0;
}

int main (int argc, const char * argv[])
{        
        const double& q = 1.0;
        const double& u = 1.0;
        
        const int& nbodies = 1024;
        const int& nproc = 8;
        const int& niter = 1;
        int x,y,z;
        x = 90;
        y = nbodies - 3*x;
        z = nbodies/4;
        
        RSIM::Sys3D mbs3D(nbodies,nproc);
        mbs3D.initDCANodesForDCAABA();        
        mbs3D.setQ(q);
        mbs3D.setU(u);
        
        DCBinaryParallelFlow dca0,dca11,dca12,dca21,dca22,dca23,dca24;        
        DCFlowTerminator dca31,dca32,dca33,dca34,dca35,dca36,dca37,dca38;
                
        // Level 0 ( 2->1)
        dca0.child1 = &dca11;dca0.child2 = &dca12;
        
        // Level 1 ( 4->2)
        dca11.child1 = &dca21;dca11.child2 = &dca22;        
        dca12.child1 = &dca23;dca12.child2 = &dca24;
        
        // Level 3 (8->4)
        dca21.child1 = &dca31;dca21.child2 = &dca32;
        dca22.child1 = &dca33;dca22.child2 = &dca34;
        dca23.child1 = &dca35;dca23.child2 = &dca36;
        dca24.child1 = &dca37;dca24.child2 = &dca38;

        CommSync sync_0_12, sync_11_22, sync_12_24, sync_21_32, sync_22_34, sync_23_36, sync_24_38;
        
        dca0.child_sync = dca12.parent_sync = &sync_0_12;
        dca11.child_sync = dca22.parent_sync = &sync_11_22;
        dca12.child_sync = dca24.parent_sync = &sync_12_24;
        dca21.child_sync = dca32.parent_sync = &sync_21_32;
        dca22.child_sync = dca34.parent_sync = &sync_22_34;
        dca23.child_sync = dca36.parent_sync = &sync_23_36;
        dca24.child_sync = dca38.parent_sync = &sync_24_38;

        // declair the calculations
        DCARoot comp0;
        DCABasic comp11, comp12, comp21, comp22, comp23, comp24;        
        DCAABA comp31,comp32,comp33,comp34,comp35,comp36,comp37,comp38;
        
        // link the computations
        dca0.computation = &comp0;      dca11.computation = &comp11;
        dca12.computation = &comp12;    dca21.computation = &comp21;
        dca22.computation = &comp22;    dca23.computation = &comp23;
        dca24.computation = &comp24;    dca31.computation = &comp31;
        dca32.computation = &comp32;    dca33.computation = &comp33;
        dca34.computation = &comp34;    dca35.computation = &comp35;
        dca36.computation = &comp36;    dca37.computation = &comp37;
        dca38.computation = &comp38;
        
        
        // associate local data with the computations
        comp0.mbs3D = &mbs3D;
        comp0.parent_id = 12;comp0.child_id = 13;comp0.asm_id = 14;  
        

        comp11.mbs3D = &mbs3D;comp11.parent_id = 8;comp11.child_id = 9;comp11.asm_id = 12;comp11.calcH2 = true;
        comp12.mbs3D = &mbs3D;comp12.parent_id = 10;comp12.child_id = 11;comp12.asm_id = 13;
        
        comp21.mbs3D = &mbs3D;comp21.parent_id = 0;comp21.child_id = 1;comp21.asm_id = 8;comp21.calcH2=true;                        
        comp22.mbs3D = &mbs3D;comp22.parent_id = 2;comp22.child_id = 3;comp22.asm_id = 9;comp22.calcH2=true;
        comp23.mbs3D = &mbs3D;comp23.parent_id = 4;comp23.child_id = 5;comp23.asm_id =10;comp23.calcH2=true;
        comp24.mbs3D = &mbs3D;comp24.parent_id = 6;comp24.child_id = 7;comp24.asm_id =11;
                        
        comp31.mbs3D = &mbs3D;  comp31.start_id = 0;    comp31.end_id = x-1;    comp31.asm_id = 0;
        comp32.mbs3D = &mbs3D;  comp32.start_id = x;    comp32.end_id = 2*x-1;  comp32.asm_id = 1;
        comp33.mbs3D = &mbs3D;  comp33.start_id = 2*x;  comp33.end_id = 3*x-1;  comp33.asm_id = 2;
        comp34.mbs3D = &mbs3D;  comp34.start_id = 3*x;  comp34.end_id = 4*x-1;  comp34.asm_id = 3;
        comp35.mbs3D = &mbs3D;  comp35.start_id = 4*x;  comp35.end_id = 5*x-1;  comp35.asm_id = 4;
        comp36.mbs3D = &mbs3D;  comp36.start_id = 5*x;  comp36.end_id = 6*x-1;  comp36.asm_id = 5;
        comp37.mbs3D = &mbs3D;  comp37.start_id = 6*x;  comp37.end_id = 7*x-1;  comp37.asm_id = 6;
        comp38.mbs3D = &mbs3D;  comp38.start_id = 7*x;  comp38.end_id = nbodies-1;  comp38.asm_id = 7;
        
        comp0.calcH2=comp12.calcH2=comp24.calcH2=comp38.calcH2=false;
                                
        pthread_attr_t attr;
        pthread_t thread1,thread2,thread3;

        pthread_attr_init(&attr);                
        pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);        
        
        //set detached so thread resources will be freed immediately upon
        // thread termination (no join needed)
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
        
        // launch the threads
        void *data = (void *) &dca12;
        pthread_create(&thread1, &attr, ThreadFunction, data);
        data = (void *) &dca22;
        pthread_create(&thread2, &attr, ThreadFunction, data);
        data = (void *) &dca24;
        pthread_create(&thread3, &attr, ThreadFunction, data);
        data = (void *) &dca32;
        pthread_create(&thread3, &attr, ThreadFunction, data);
        data = (void *) &dca34;
        pthread_create(&thread3, &attr, ThreadFunction, data);
        data = (void *) &dca36;
        pthread_create(&thread3, &attr, ThreadFunction, data);
        data = (void *) &dca38;
        pthread_create(&thread3, &attr, ThreadFunction, data);

        //clean-up the attributes
        pthread_attr_destroy(&attr);        
        mbs3D.updRotationMatrix();
        mbs3D.updAngularVelocity();
        
        RSIM::Timer t;                
        for(int i=0;i<niter;i++)
        {        
                // run the root subsystem
//                 dca0.kinAssembly_traversal();
//                 dca0.kinSolve_traversal();
//                 dca0.EOM_traversal();
                dca0.assembly_traversal();        
                dca0.solve_traversal();                

        }    
        t.stop();
//         t.printElapsedTime(0);                
        cout<<setprecision(16);
        mbs3D.displayUDot();      

        exit(0);
        return 0;
}
